import pygame 
from settings import *
from player import Player
from overlay import Overlay
from sprites import Generic, Water, WildFlower, Tree, Interaction, Particle
from pytmx.util_pygame import load_pygame
from support import *
from transition import Transition
from soil import SoilLayer
from sky import Rain, Sky
from random import randint
from menu import Menu

"""
游戏各种对象和逻辑封装在该类内
属性：  
函数：
"""
class Level:
	# 初始化信息
	def __init__(self):
		# 获取当前显示窗口的 Surface 对象(即游戏屏幕)，获取到对象后可在屏幕上绘图
		self.display_surface = pygame.display.get_surface()
		# sprite groups(游戏对象组)
		self.all_sprites = CameraGroup()
		"""
		pygame.sprite.Group():用于管理和操作精灵（Sprite）对象的集合
		下面是一些常用的 Group 类方法：
			add(sprite)：将一个精灵对象添加到组中。
			remove(sprite)：从组中移除指定的精灵对象。
			sprites()：返回组中所有的精灵对象。
			update(*args)：调用组中每个精灵对象的 update() 方法，用于更新精灵的状态。
			draw(surface)：将组中的每个精灵对象绘制到指定的显示窗口表面（surface）上。
		"""
		self.collision_sprites = pygame.sprite.Group()      # 碰撞
		self.tree_sprites = pygame.sprite.Group()           # 树
		self.interaction_sprites = pygame.sprite.Group()    # 交互
		# 创立游戏对象
		self.soil_layer = SoilLayer(self.all_sprites, self.collision_sprites)
		self.setup()
		self.overlay = Overlay(self.player)
		self.transition = Transition(self.reset, self.player)
		# sky(天气:控制下雨天，以及下雨天影响耕种土地)
		self.rain = Rain(self.all_sprites)
		self.raining = randint(0, 10) > 7     # 是否下雨：True下雨，False晴天
		self.soil_layer.raining = self.raining
		self.sky = Sky()
		# shop(主菜单，购买种子和出售物品)
		self.menu = Menu(self.player, self.toggle_shop)
		self.shop_active = False   # 是否处于商店状态

		# music(设置游戏背景音乐)
		self.success = pygame.mixer.Sound('../audio/success.wav')
		self.success.set_volume(0.1)  # 设置音量大小
		self.music = pygame.mixer.Sound('../audio/music.mp3')
		self.music.set_volume(0.4)
		self.music.play(loops=-1)

	# 创建游戏对象
	def setup(self):
		# 获取游戏相关数据(地图上的障碍物)[tmx_data 是一个 TMX 格式的地图数据对象]
		tmx_data = load_pygame('../data/map.tmx')

		# 绘制房子
		for layer in ['HouseFloor', 'HouseFurnitureBottom']:    # 地板和地毯
			"""
			get_layer_by_name(layer) 是用于根据图层名获取对应图层的方法
			tiles() 是用于获取指定图层上的所有瓦片（Tile）的方法
			"""
			for x, y, surf in tmx_data.get_layer_by_name(layer).tiles():
				Generic((x * TILE_SIZE, y * TILE_SIZE), surf, self.all_sprites, LAYERS['house bottom'])
		for layer in ['HouseWalls', 'HouseFurnitureTop']:    # 墙和家具
			for x,y,surf in tmx_data.get_layer_by_name(layer).tiles():
				Generic((x * TILE_SIZE, y * TILE_SIZE), surf, self.all_sprites)

		# 绘制栅栏
		for x, y, surf in tmx_data.get_layer_by_name('Fence').tiles():
			Generic((x * TILE_SIZE, y * TILE_SIZE), surf, [self.all_sprites, self.collision_sprites])

		# 绘制水
		water_frames = import_folder('../graphics/water')
		for x, y, surf in tmx_data.get_layer_by_name('Water').tiles():
			Water((x * TILE_SIZE, y * TILE_SIZE), water_frames, self.all_sprites)
		# 绘制树
		for obj in tmx_data.get_layer_by_name('Trees'):
			Tree(pos=(obj.x, obj.y),
				 surf=obj.image,
				 groups=[self.all_sprites, self.collision_sprites, self.tree_sprites],
				 name=obj.name,
				 player_add=self.player_add)

		# 绘制野花
		for obj in tmx_data.get_layer_by_name('Decoration'):
			WildFlower((obj.x, obj.y), obj.image, [self.all_sprites, self.collision_sprites])

		# 碰撞边界
		for x, y, surf in tmx_data.get_layer_by_name('Collision').tiles():
			Generic((x * TILE_SIZE,y * TILE_SIZE), pygame.Surface((TILE_SIZE, TILE_SIZE)), self.collision_sprites)
		# 玩家
		for obj in tmx_data.get_layer_by_name('Player'):
			if obj.name == 'Start':
					self.player = Player(pos=(obj.x, obj.y),
										 group=self.all_sprites,
										 collision_sprites=self.collision_sprites,
										 tree_sprites=self.tree_sprites,
										 interaction = self.interaction_sprites,
										 soil_layer= self.soil_layer,
										 toggle_shop=self.toggle_shop)
			if obj.name == 'Bed':
				Interaction((obj.x, obj.y), (obj.width, obj.height), self.interaction_sprites, obj.name)

			if obj.name == 'Trader':
				Interaction((obj.x, obj.y), (obj.width, obj.height), self.interaction_sprites, obj.name)

		Generic(pos=(0, 0),
				surf=pygame.image.load('../graphics/world/ground.png').convert_alpha(),
				groups=self.all_sprites,
				z=LAYERS['ground'])

	# 玩家库存物品增加
	def player_add(self, item):
		print(f'>收集{item},库存加1')
		self.player.item_inventory[item] += 1
		self.success.play()

	# 商店菜单
	def toggle_shop(self):
		print(f'>>商场菜单状态切换{self.shop_active} -> {not self.shop_active}')
		self.shop_active = not self.shop_active
	# 重置
	def reset(self):
		print(f'>>>新的一天 -> 重置游戏状态')
		# plant
		self.soil_layer.update_plants()
		# soil
		self.soil_layer.remove_water()
		self.raining = randint(0, 10) > 6
		# 下雨天随机
		self.soil_layer.raining = self.raining
		if self.raining:
			self.soil_layer.water_all()

		# apples on the tree
		for tree in self.tree_sprites.sprites():
			print(">>>>><<<<<<    苹果")
			for apple in tree.apple_sprites.sprites():
				print(f'消除苹果')
				apple.kill()
			tree.create_fruit()

		# sky
		self.sky.start_color = [255, 255, 255]
	# 与自己栽的植物碰撞
	def plant_collision(self):
		if self.soil_layer.plant_sprites:
			for plant in self.soil_layer.plant_sprites.sprites():
				if plant.harvestable and plant.rect.colliderect(self.player.hitbox):
					print(f">>>>采集果实{plant}")
					self.player_add(plant.plant_type)
					plant.kill()
					Particle(plant.rect.topleft, plant.image, self.all_sprites, z=LAYERS['main'])
					self.soil_layer.grid[plant.rect.centery // TILE_SIZE][plant.rect.centerx // TILE_SIZE].remove('P')
	def run(self, dt):
		# 绘制游戏窗口
		self.display_surface.fill('black')   # 填充游戏窗口
		# self.all_sprites.draw(self.display_surface)
		self.all_sprites.custom_draw(self.player)

		# update
		if self.shop_active:
			self.menu.update()
		else:
			self.all_sprites.update(dt)    # 所有游戏对象更新
			self.plant_collision()

		# weather
		self.overlay.display()

		# rain
		if self.raining and not self.shop_active:   # 进入菜单时关闭下雨状态
			self.rain.update()

		# daytime
		self.sky.display(dt)

		# transition overlay
		if self.player.sleep:
			self.transition.play()



"""
自定义相机类
继承自 pygame.sprite.Group。在游戏开发中，相机用于跟踪游戏世界中的元素，并将它们绘制在游戏窗口上，以实现视角移动效果
"""
class CameraGroup(pygame.sprite.Group):
	def __init__(self):
		super().__init__()
		# self.display_surface 是一个 Pygame 显示窗口的 Surface 对象，它是你创建的游戏窗口
		self.display_surface = pygame.display.get_surface()
		# 是 Pygame 中的一个类，用于表示二维向量。向量是具有大小和方向的数学对象，可以用于在游戏中表示位置、速度、加速度等
		self.offset = pygame.math.Vector2()
	def custom_draw(self,player):
		# 确保玩家始终在相机的中心
		self.offset.x = player.rect.centerx - SCREEN_WIDTH / 2
		self.offset.y = player.rect.centery - SCREEN_HEIGHT / 2

		# 按层级大小依次绘制图像
		for layer in LAYERS.values():
			# 按照y轴的坐标先后绘制
			for sprite in sorted(self.sprites(), key=lambda sprite: sprite.rect.centery):
				if sprite.z == layer:
					offset_rect = sprite.rect.copy()
					offset_rect.center -= self.offset
					'''
					来在屏幕上绘制精灵（Sprite）的方法
					image: 代表精灵图像的 Surface 对象
					rect: 代表精灵位置和大小的矩形对象
					通过调用 blit() 方法，可以将精灵的图像绘制到显示窗口的指定位置上
					'''
					self.display_surface.blit(sprite.image, offset_rect)